﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks.Sources;
using LxBasic;

namespace LxLESS
{
    internal class MGZoneCreator
    {
        //Flag----
        protected readonly int Flag_InNone = -1;
        protected readonly int Flag_InGroup = -2;
        protected readonly int Flag_InTempCell = -3;
        //>0时为分配到的粗网格Id
        //Flag----end
        //设置
        int MergeCells;
        IBuildMGZone finezone;
        //临时存储
        int[] CellFlags;

        //结果存储;
        public List<MGTemp.Cell> coarseCells;
        public List<MGTemp.Face> coarseInnFaces;
        public List<MGTemp.Face> coarseBouFaces;
        public MGTemp.CellToStoreFace[] coarseCellsToStoreFace;
        public MGZone CreateMGZone(IBuildMGZone finezone, int mergeCells)
        {
            this.finezone = finezone;
            this.MergeCells = mergeCells > 1 ? mergeCells : 4;

            MGZone MgZone = new MGZone();

            initialize();
            createMGCellTemp();
            coarseCellsToStoreFace = new MGTemp.CellToStoreFace[coarseCells.Count];
            for (int i1 = 0; i1 < coarseCellsToStoreFace.Length; i1++)
            {
                coarseCellsToStoreFace[i1] = new MGTemp.CellToStoreFace();
            }
            createInnerCoarseFaces();
            int boundCount = finezone.GetBoundsCount();
            MgZone.Bounds = new IndexRange[boundCount];
            for (int i1 = 0; i1 < finezone.GetBoundsCount(); i1++)
            {
                MgZone.Bounds[i1] = createBoundCoarseFacesAndCells(finezone.GetBoundIdx(i1));
            }
            convertToMGZone(MgZone);
            return MgZone;
        }
        #region 内部粗网格划分         
        protected void initialize()
        {
            CheckCreator.ArrayEnough(ref CellFlags, finezone.GetInnerIdx().CellIdx.GetCount());
            Array.Fill(CellFlags, Flag_InNone);

            coarseCells = new();
            coarseInnFaces = new();
            coarseBouFaces = new();
        }
        protected void createMGCellTemp()
        {
            int groupMaxCount = 10 * MergeCells;
            List<int> group = new List<int>(groupMaxCount);
            List<int> cells = new List<int>(MergeCells);
            (int i1, int end) = finezone.GetInnerIdx().CellIdx.Get();
            for (; i1 < end;)
            {
                if (CellFlags[i1] == Flag_InNone)
                {
                    group.Clear();
                    addAdjCell(group, i1, groupMaxCount, Flag_InNone, Flag_InGroup);
                    if (group.Count > MergeCells)
                    {
                        splitGroupToManyCells(group, cells);
                    }
                    else if (group.Count > 0.5 * MergeCells)
                    {
                        listToTempCell(group);
                    }
                    else
                    {
                        addGroupToOtherCoarse(group);
                    }
                }
                else
                {
                    i1++;
                }
            }
        }
        void splitGroupToManyCells(List<int> group, List<int> cells)
        {
            foreach (var gc in group)
            {
                if (CellFlags[gc] == Flag_InGroup)
                {
                    cells.Clear();
                    addAdjCell(cells, gc, MergeCells, Flag_InGroup, Flag_InTempCell);
                    if (cells.Count > MergeCells / 2)
                    {
                        listToTempCell(cells);
                    }
                    else
                    {
                        //放虎归山
                        foreach (var c in cells)
                        {
                            CellFlags[c] = Flag_InNone;
                        }
                    }

                }
            }
        }
        void addAdjCell(List<int> container, int core, int count, int FLAG_BeforeAdd, int FLAG_AfterAdd)
        {
            container.Clear();
            container.Add(core);//这里面第一个添加的不检查
            CellFlags[core] = FLAG_AfterAdd;
            int groupBoundStart = 0;
            while (groupBoundStart < container.Count)//没有新的边界了
            {
                int end = container.Count;
                for (int i1 = groupBoundStart; i1 < end; i1++)
                {
                    foreach (var adj in finezone.GetInnCellAdjInnCelll(container[i1]))
                    {
                        if (CellFlags[adj] == FLAG_BeforeAdd)
                        {
                            container.Add(adj);
                            CellFlags[adj] = FLAG_AfterAdd;
                            if (container.Count >= count) return;//group满了
                        }
                    }
                }
                groupBoundStart = end;
            }
        }
        void listToTempCell(List<int> toAdd)
        {
            foreach (var c in toAdd)
            {
                CellFlags[c] = coarseCells.Count;
            }
            coarseCells.Add(new MGTemp.Cell()
            {
                FineCells = new List<int>(toAdd)
            });
        }
        void addGroupToOtherCoarse(List<int> group)
        {
            int groupleft;
            do
            {
                groupleft = group.Count;
                for (int i1 = 0; i1 < group.Count;)
                {
                    int cell = group[i1];
                    (int adjMinCoarseCell, int adjMinCoarseCellCount) = findAdjToAppend(cell);
                    if (adjMinCoarseCellCount == int.MaxValue)
                    {
                        i1++;
                    }
                    else
                    {
                        CellFlags[cell] = adjMinCoarseCell;
                        coarseCells[adjMinCoarseCell].FineCells.Add(cell);
                        group.RemoveAt(i1);
                    }
                }

            } while (group.Count < groupleft);//能加到别处加到别处
                                              //不能加到别处的
            if (group.Count > 0)
            {
                listToTempCell(group);
            }
        }
        (int adjMinCoarseCell, int adjMinCoarseCellCount) findAdjToAppend(int c)
        {
            int adjMinCoarseCell = 0;
            int adjMinCoarseCellCount = int.MaxValue;
            foreach (var adj in finezone.GetInnCellAdjInnCelll(c))
            {
                int cellFlag = CellFlags[adj];
                if (cellFlag > 0)
                {
                    var coarseCell = coarseCells[cellFlag];
                    if (coarseCell.FineCells.Count < adjMinCoarseCellCount)
                    {
                        adjMinCoarseCell = cellFlag;
                        adjMinCoarseCellCount = coarseCell.FineCells.Count;
                    }
                }
            }
            return (adjMinCoarseCell, adjMinCoarseCellCount);
        }
        #endregion
        private void createInnerCoarseFaces()
        {
            //1.add fine fact to coarseCell
            (int i1, int end) = finezone.GetInnerIdx().FaceIdx.Get();//.GetInnerFaceIdx();
            for (; i1 < end; i1++)
            {
                (int oCell, int nCell) = finezone.GetInnFaceAdjCell(i1);
                addToFace(i1, CellFlags[oCell], CellFlags[nCell]);
            }
            void addToFace(int i1, int oCell, int nCell)
            {
                if (oCell == nCell)
                {
                    coarseCells[oCell].InnerFineFaces.Add(i1);
                }
                else if (oCell < nCell)//默认Face存储到小编号的粗网格中
                {

                    foreach (var ccf in coarseCellsToStoreFace[oCell].CoarseOFaces)
                    {
                        if (ccf.NSideCell == nCell)
                        {
                            ccf.FineFace_O2N.Add(i1);
                            return; ;
                        }
                    }
                    MGTemp.Face ccfnew = new()
                    {
                        OSideCell = oCell,
                        NSideCell = nCell,
                    };
                    ccfnew.FineFace_O2N.Add(i1);
                    coarseCellsToStoreFace[oCell].CoarseOFaces.Add(ccfnew);
                }
                else
                {
                    foreach (var ccf in coarseCellsToStoreFace[nCell].CoarseOFaces)
                    {
                        if (ccf.NSideCell == oCell)
                        {
                            ccf.FineFace_N2O.Add(i1);
                            return;
                        }
                    }
                    MGTemp.Face ccfnew = new()
                    {
                        OSideCell = nCell,
                        NSideCell = oCell,
                    };
                    ccfnew.FineFace_N2O.Add(i1);
                    coarseCellsToStoreFace[nCell].CoarseOFaces.Add(ccfnew);
                }
            }
            //2.
            moveCoarseFacesFromCellStorageToList(coarseInnFaces);
        }

        private IndexRange createBoundCoarseFacesAndCells(IndexRange faceIDs)
        {
            int coarseStart = coarseBouFaces.Count;
            (int i1, int end) = faceIDs.Get();//.GetInnerFaceIdx();
            for (; i1 < end; i1++)
            {
                int oCell = finezone.GetBouFaceOSideCell(i1);
                oCell = CellFlags[oCell];
                var list = coarseCellsToStoreFace[oCell].CoarseOFaces;
                if (list.Count == 0)
                {
                    MGTemp.Face coarsefacetemp = new()
                    {
                        OSideCell = oCell,
                    };
                    coarsefacetemp.FineFace_O2N.Add(i1);
                    list.Add(coarsefacetemp);
                }
                else
                {
                    list[0].FineFace_O2N.Add(i1);
                }
            }
            moveCoarseFacesFromCellStorageToList(coarseBouFaces);
            return new IndexRange(coarseStart, coarseBouFaces.Count);
        }
        private void moveCoarseFacesFromCellStorageToList(List<MGTemp.Face> list)
        {
            foreach (var coarsecell in coarseCellsToStoreFace)
            {
                if (coarsecell.CoarseOFaces.Count != 0)
                {
                    list.AddRange(coarsecell.CoarseOFaces);
                    coarsecell.CoarseOFaces.Clear();
                }
            }
        }
        private void convertToMGZone(MGZone mgZone)
        {
            //添加face信息
            MGInnFace[] mgInnFaces = new MGInnFace[coarseInnFaces.Count];
            MGBouFace[] mgBouFaces = new MGBouFace[coarseBouFaces.Count];
            MGCell[] mgInnCells = new MGCell[coarseCells.Count];
            AssignFaceToCellTool tool = new AssignFaceToCellTool(mgInnCells.Length, mgInnFaces.Length, mgBouFaces.Length);
            for (int i1 = 0; i1 < mgInnFaces.Length; i1++)
            {
                ref var f = ref mgInnFaces[i1];
                var f2 = coarseInnFaces[i1];
                f = new MGInnFace()
                {
                    OSideCell = f2.OSideCell,
                    NSideCell = f2.NSideCell,
                    FineFaces_O2N = f2.FineFace_O2N.ToArray(),
                    FineFaces_N2O = f2.FineFace_N2O.ToArray(),
                };
                tool.AssignInnFaceToCell(f.OSideCell, f.NSideCell, i1);
            }
            for (int i1 = 0; i1 < mgBouFaces.Length; i1++)
            {
                ref var f = ref mgBouFaces[i1];
                var f2 = coarseBouFaces[i1];
                f = new MGBouFace()
                {
                    OSideCell = f2.OSideCell,
                    FineSides = f2.FineFace_O2N.ToArray(),
                };
                tool.AssignBouFacesToCell(f.OSideCell, i1);
            }
            for (int i1 = 0; i1 < mgInnCells.Length; i1++)
            {
                ref var c = ref mgInnCells[i1];
                var f2 = coarseCells[i1];
                c = new MGCell()
                {
                    InnerFineFaces = f2.InnerFineFaces.ToArray(),
                    FineCells = f2.FineCells.ToArray(),
                };
                (c.AdjFaces, c.InnOFaceEnd, c.InnNFaceEnd) = tool.GetFaces(i1);
            }
            mgZone.InnCells = mgInnCells;
            mgZone.InnFaces = mgInnFaces;
            mgZone.BouFaces = mgBouFaces;
        }
    }
}
//public void checkTopology()
//{
//    //foreach (var coarseIndex in coarseZone.Bounds)
//    //{
//    //    for (int i1 = coarseIndex.CellIdx.Start; i1 < coarseIndex.CellIdx.EndP1; i1++)
//    //    {
//    //        foreach (var fc in coarseCells[i1].FineCells)
//    //        {
//    //            InCoarseCell[fc] = i1;
//    //        }
//    //    }
//    //}
//    int fineFaceCountInFineZone = 0, fineCellCountInFineZone = 0;
//    fineCellCountInFineZone += finezone.GetInnerIdx().cellIdx.GetCount();
//    fineFaceCountInFineZone += finezone.GetInnerIdx().faceIdx.GetCount();
//    for (int i1 = 0; i1 < finezone.GetBoundsCount(); i1++)
//    {
//        fineCellCountInFineZone += finezone.GetBoundIdx(i1).cellIdx.GetCount();// ind.CellIDs.End - ind.CellIDs.Start + 1;
//        fineFaceCountInFineZone += finezone.GetBoundIdx(i1).faceIdx.GetCount();// ind.FaceIDs.End - ind.FaceIDs.Start + 1;
//    }
//    int fineCellCountInCoarse = 0;
//    for (int i1 = 0; i1 < coarseZone.InnCells.Length; i1++)
//    {
//        for (int i2 = 0; i2 < coarseZone.InnCells[i1].FineCells.Length; i2++)
//        {
//            fineCellCountInCoarse++;
//            if (CellFlags[coarseZone.InnCells[i1].FineCells[i2]] != i1)
//                Debug.WriteLine("AMG error in coarse {0} in fine {1}", i1, coarseZone.InnCells[i1].FineCells[i2]);
//        }
//    }
//    if (fineCellCountInCoarse != fineCellCountInFineZone)
//    {

//        Debug.WriteLine("AMG error finecellcount inIndex:{0} inCoarse:{1}", fineCellCountInFineZone, fineCellCountInCoarse);
//    }
//    for (int i1 = 0; i1 < coarseZone.InnCells.Length; i1++)//检查粗网格面与网格对应关系
//    {
//        for (int i2 = 0; i2 < coarseZone.InnCells[i1].OFaces.Length; i2++)
//        {
//            if (coarseZone.InnFaces[coarseZone.InnCells[i1].OFaces[i2]].OSideCell != i1)
//                Debug.WriteLine("AMG error in coarseface");
//        }
//        for (int i2 = 0; i2 < coarseZone.InnCells[i1].NFaces.Length; i2++)
//        {
//            if (coarseZone.InnFaces[coarseZone.InnCells[i1].NFaces[i2]].NSideCell != i1)
//                Debug.WriteLine("AMG error in coarseface");
//        }
//    }
//    int fineFaceCountInCoarse = 0;
//    for (int i1 = 0; i1 < coarseZone.InnCells.Length; i1++)//检查粗网格内部面
//    {
//        foreach (var ii in coarseZone.InnCells[i1].InnerFineFaces)
//        {
//            fineFaceCountInCoarse++;
//            TopologicalFace on = finezone.GetInnFaceAdjCell(ii);
//            if (CellFlags[on.Owner] != i1 || CellFlags[on.Neighbor] != i1)
//                Debug.WriteLine("AMG error in face");
//        }
//    }
//    for (int i1 = 0; i1 < coarseZone.InnFaces.Length; i1++)//检查粗网格交界面
//    {
//        for (int i2 = 0; i2 < coarseZone.InnFaces[i1].FineFaces_O2N.Length; i2++)
//        {
//            fineFaceCountInCoarse++;
//            TopologicalFace on = finezone.GetInnFaceAdjCell(coarseZone.InnFaces[i1].FineFaces_O2N[i2]);
//            if (CellFlags[on.Owner] != coarseZone.InnFaces[i1].OSideCell || CellFlags[on.Neighbor] != coarseZone.InnFaces[i1].NSideCell)
//                Debug.WriteLine("AMG error in face");
//        }
//        for (int i2 = 0; i2 < coarseZone.InnFaces[i1].FineFaces_N2O.Length; i2++)
//        {
//            fineFaceCountInCoarse++;
//            TopologicalFace on = finezone.GetInnFaceAdjCell(coarseZone.InnFaces[i1].FineFaces_N2O[i2]);
//            if (CellFlags[on.Owner] != coarseZone.InnFaces[i1].NSideCell || CellFlags[on.Neighbor] != coarseZone.InnFaces[i1].OSideCell)
//                Debug.WriteLine("AMG error in face");
//        }
//    }
//    if (fineFaceCountInCoarse != fineFaceCountInFineZone)
//    {
//        Debug.WriteLine("AMG error finefacecount inIndex:{0} inCoarse:{1}", fineFaceCountInFineZone, fineFaceCountInCoarse);
//    }
//}

//先把原先已添加的innerFace加上
//IndexRecorder innerCellIDs = coarseZone.InnerIndex.CellIDs;
//for (int i1 = innerCellIDs.Start; i1 <= innerCellIDs.End; ++i1)
//{
//    this.QueueTool_N.ConvertQueueToArray(out structCells[i1].InnerFineFaces, i1);
//}
//for (int i1 = innerCellIDs.End + 1; i1 < structCells.Length; ++i1)
//{
//    structCells[i1].InnerFineFaces = new int[0];
//}
//QueueTool_N.Reset();
//QueueTool_O.Create(structCells.Length, structFaces.Length);
//QueueTool_N.Create(structCells.Length, structFaces.Length);
//for (int i1 = 0; i1 < structFaces.Length; ++i1)
//{
//    QueueTool_O.AddOneToQueue(structFaces[i1].OSideCell, i1);
//    QueueTool_N.AddOneToQueue(structFaces[i1].NSideCell, i1);
//}
//for (int i1 = 0; i1 < structCells.Length; ++i1)
//{
//    QueueTool_O.ConvertQueueToArray(out structCells[i1].OFaces, i1);
//    QueueTool_N.ConvertQueueToArray(out structCells[i1].NFaces, i1);
//}